package org.ruoyi.gathe.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.data.mapper.DataHandleMapper;
import org.ruoyi.gathe.domain.GatheTable;
import org.ruoyi.gathe.domain.GatheTableColumn;
import org.ruoyi.gathe.domain.bo.GatheTableBo;
import org.ruoyi.gathe.domain.bo.GatheTableColumnBo;
import org.ruoyi.gathe.domain.vo.GatheTableColumnVo;
import org.ruoyi.gathe.domain.vo.GatheTableVo;
import org.ruoyi.gathe.mapper.GatheDistanceMapper;
import org.ruoyi.gathe.mapper.GatheLocalMapper;
import org.ruoyi.gathe.mapper.GatheTableColumnMapper;
import org.ruoyi.gathe.mapper.GatheTableMapper;
import org.ruoyi.gathe.service.IGatheService;
import org.ruoyi.gathe.service.IGatheTableColumnService;
import org.ruoyi.gathe.service.IGatheTableService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 采集数据Service业务层处理
 *
 * @author bz_huaYal9146
 * @date 2025-11-06
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class GatheServiceImpl implements IGatheService {

    private final GatheLocalMapper localMapper;
    private final GatheDistanceMapper distanceMapper;
    private final GatheTableMapper gatheTableMapper;
    private final GatheTableColumnMapper gatheTableColumnMapper;
    private final IGatheTableService gatheTableService;
    private final IGatheTableColumnService gatheTableColumnService;

    /**
     * 采集数据
     * @return
     */
    @Override
    //@Transactional(rollbackFor = Exception.class)
    public R collect() {
        try {
            // 1、查询所有有效的GatheTable主表配置
            GatheTableBo queryBo = new GatheTableBo();
            List<GatheTableVo> gatheTableList = gatheTableService.queryList(queryBo);
            
            if (gatheTableList == null || gatheTableList.isEmpty()) {
                return R.ok("没有需要采集的配置");
            }

            int totalSuccess = 0;
            int totalFailed = 0;
            List<String> errorMessages = new ArrayList<>();

            // 2、遍历每个配置进行采集
            for (GatheTableVo gatheTableVo : gatheTableList) {
                try {
                    // 2.1 查询该配置对应的字段列表
                    GatheTableColumnBo columnBo = new GatheTableColumnBo();
                    columnBo.setGatheTableId(gatheTableVo.getId());
                    List<GatheTableColumnVo> columnList = gatheTableColumnService.queryList(columnBo);
                    
                    if (columnList == null || columnList.isEmpty()) {
                        log.warn("表配置ID: {} 没有配置字段信息，跳过采集", gatheTableVo.getId());
                        continue;
                    }

                    // 2.2 构建远端查询字段列表（使用远端字段名）
                    List<String> distanceColumns = columnList.stream()
                        .filter(col -> StringUtils.isNotBlank(col.getGatheColumnFar()))
                        .map(GatheTableColumnVo::getGatheColumnFar)
                        .collect(Collectors.toList());
                    
                    if (distanceColumns.isEmpty()) {
                        log.warn("表配置ID: {} 没有有效的远端字段配置，跳过采集", gatheTableVo.getId());
                        continue;
                    }

                    // 2.3 构建本地插入字段列表（使用本地字段名）
                    List<String> localColumns = columnList.stream()
                        .filter(col -> StringUtils.isNotBlank(col.getGatheColumn()))
                        .map(GatheTableColumnVo::getGatheColumn)
                        .collect(Collectors.toList());

                    // 2.4 构建查询条件（根据规则公式）
                    String whereClause = buildWhereClause(gatheTableVo);
                    
                    // 2.5 从远端数据库查询数据
                    String distanceTableName = gatheTableVo.getGatheTable();
                    String distanceColumnsStr = String.join(",", distanceColumns);
                    String whereClauseWithKeyword = StringUtils.isNotBlank(whereClause) ? " WHERE " + whereClause : "";
                    
                    log.info("开始采集表: {}, 查询条件: {}", distanceTableName, whereClauseWithKeyword);
                    List<Map<String, Object>> distanceDataList = distanceMapper.selectByTableName(
                        distanceTableName, 
                        distanceColumnsStr, 
                        whereClauseWithKeyword
                    );

                    if (distanceDataList == null || distanceDataList.isEmpty()) {
                        log.info("表: {} 没有查询到数据", distanceTableName);
                        continue;
                    }

                    // 2.6 字段映射：将远端字段名映射到本地字段名
                    List<Map<String, Object>> mappedDataList = new ArrayList<>();
                    for (Map<String, Object> distanceRow : distanceDataList) {
                        Map<String, Object> mappedRow = new java.util.HashMap<>();
                        for (GatheTableColumnVo column : columnList) {
                            if (StringUtils.isNotBlank(column.getGatheColumnFar()) && 
                                StringUtils.isNotBlank(column.getGatheColumn())) {
                                Object value = distanceRow.get(column.getGatheColumnFar());
                                mappedRow.put(column.getGatheColumn(), value);
                            }
                        }
                        mappedDataList.add(mappedRow);
                    }

                    // 2.7 插入数据到本地数据库
                    String localTableName = gatheTableVo.getGatheTable(); // 本地表名与远端表名相同
                    String localColumnsStr = String.join(",", localColumns);
                    
                    // 批量插入数据
                    int insertedCount = batchInsertByTableName(localTableName, localColumnsStr, mappedDataList);

                    totalSuccess += insertedCount;
                    log.info("表: {} 采集成功，插入 {} 条数据", distanceTableName, insertedCount);

                } catch (Exception e) {
                    totalFailed++;
                    String errorMsg = String.format("表配置ID: %s, 表名: %s, 错误: %s", 
                        gatheTableVo.getId(), gatheTableVo.getGatheTable(), e.getMessage());
                    errorMessages.add(errorMsg);
                    log.error(errorMsg, e);
                }
            }

            // 3、返回采集结果
            String message = String.format("采集完成！成功: %d 条，失败: %d 个配置", totalSuccess, totalFailed);
            if (!errorMessages.isEmpty()) {
                message += "。失败详情: " + String.join("; ", errorMessages);
            }
            return R.ok(message);

        } catch (Exception e) {
            log.error("采集数据异常", e);
            return R.fail("采集数据失败: " + e.getMessage());
        }
    }

    /**
     * 构建查询条件（根据规则公式）
     * 
     * @param gatheTableVo 采集表配置
     * @return WHERE子句（不含WHERE关键字）
     */
    private String buildWhereClause(GatheTableVo gatheTableVo) {
        if (StringUtils.isBlank(gatheTableVo.getGatheTableColumn()) || 
            StringUtils.isBlank(gatheTableVo.getGatheFormula()) ||
            StringUtils.isBlank(gatheTableVo.getGatheFormulaValue())) {
            return "";
        }

        String column = gatheTableVo.getGatheTableColumn();
        String formula = gatheTableVo.getGatheFormula();
        String formulaValue = gatheTableVo.getGatheFormulaValue();

        try {
            int value = Integer.parseInt(formulaValue);
            LocalDate today = LocalDate.now();
            LocalDate targetDate = null;

            switch (formula.toLowerCase()) {
                case "day":
                    targetDate = today.plusDays(value);
                    break;
                case "week":
                    targetDate = today.plusWeeks(value);
                    break;
                case "month":
                    targetDate = today.plusMonths(value);
                    break;
                default:
                    log.warn("不支持的规则公式: {}", formula);
                    return "";
            }

            // 构建日期范围查询条件（假设是日期字段）
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String dateStr = targetDate.format(formatter);
            
            if (value < 0) {
                // 往前的值，查询小于等于目标日期的数据
                return String.format("%s <= '%s'", column, dateStr);
            } else {
                // 往后的值，查询大于等于目标日期的数据
                return String.format("%s >= '%s'", column, dateStr);
            }
        } catch (NumberFormatException e) {
            log.warn("规则值格式错误: {}", formulaValue);
            return "";
        }
    }

    /**
     * 批量插入数据到本地表（逐条插入）
     *
     * @param tableName 表名
     * @param columns   字段列表（逗号分隔）
     * @param dataList  数据列表
     * @return 插入行数
     */
    private int batchInsertByTableName(String tableName, String columns, List<Map<String, Object>> dataList) {
        if (dataList == null || dataList.isEmpty()) {
            return 0;
        }
        int totalInserted = 0;
        String[] columnArray = columns.split(",");
        for (Map<String, Object> row : dataList) {
            StringBuilder valuesBuilder = new StringBuilder("(");
            for (int j = 0; j < columnArray.length; j++) {
                if (j > 0) {
                    valuesBuilder.append(",");
                }
                String column = columnArray[j].trim();
                Object value = row.get(column);
                if (value == null) {
                    valuesBuilder.append("NULL");
                } else if (value instanceof String) {
                    valuesBuilder.append("'").append(value.toString().replace("'", "''")).append("'");
                } else if (value instanceof Number) {
                    valuesBuilder.append(value);
                } else {
                    valuesBuilder.append("'").append(value.toString().replace("'", "''")).append("'");
                }
            }
            valuesBuilder.append(")");
            int count = localMapper.insertByTableName(tableName, columns, valuesBuilder.toString());
            totalInserted += count;
        }
        return totalInserted;
    }
}
